// Shadow Gears for WLK 3.1

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>



void zerobest(void);
void printbest(void);
void keepbest(double dps, double hit, double crit, double critpercent, double hast, double sp, int gear[]);


// {SP,hit,crit,haste,int,spi,red,yellow,blue,bonustype,bonusvalue,T8}
int itemdata[][12]={

//Helm
{113,0,70,66,76,0,1,0,0,4,8,1},      // T8
{115,0,59,0,66,80,0,0,1,0,9,0},   // Yogg
{131,0,69,0,92,70,1,0,0,-1,0,0},   // Mimiron
{114,51,0,68,87,0,0,0,1,0,9,0},   // Razorscale

//Neck
{74,0,41,31,43,0,0,1,0,2,4,0},   // Thorim 10 Hard
{75,0,0,35,48,47,1,0,0,5,4,0},   // Iron Council Hard
{74,0,0,40,36,37,0,1,0,2,4,0},   // Iron Council 10 Hard
{75,46,0,41,51,0,0,1,0,0,5,0},   // Flame Leviathan Hard

//Shoulders
{90,0,62,0,65,49,1,0,0,0,5,1},   // t8
{100,0,0,62,49,42,1,1,0,-1,0,0},   // Yogg 10 Hard
{78,41,0,50,57,0,1,0,0,-1,0,0},   // T7
{90,0,41,0,56,62,0,1,0,4,4,0},   // Vezax
{90,52,0,0,65,49,0,0,1,0,5,0},   // Ignis

//Cloak
{75,0,0,39,48,48,0,0,1,-1,0,0},   // Algalon quest reward
{64,0,34,42,46,0,0,0,1,0,5,0},   // Sarth 2D+
{74,0,49,0,42,42,0,0,0,-1,0,0},   // Mimiron
{75,41,43,0,51,0,0,1,0,0,5,0},   // Iron Council Hard

//Chest
{132,74,0,58,76,0,0,1,1,2,6,1},   // T8
{123,0,58,82,86,0,0,0,1,0,5,0},   // Kologarn
{115,0,0,70,81,57,1,0,1,3,6,0},   // Iron Council
{99,0,0,66,77,51,1,0,1,3,6,0},   // Sarth 1D+

//Bracers
{75,0,0,39,52,48,1,0,0,5,4,0},   // XT002 Hard
{64,0,0,34,46,42,1,0,0,5,4,0},   // Sarth 2D+
{74,0,42,0,42,49,0,0,0,-1,0,0},   // Razorscale
{74,36,0,42,46,0,0,0,0,-1,0,0},   // Kologarn

//Gloves
{99,0,64,0,44,54,0,1,0,1,4,1},   // T8
{92,0,74,0,72,64,0,2,0,0,7,0},   // Vezax Hard
{78,0,56,41,53,0,0,1,0,2,6,0},   // T7

//Belt
{81,0,48,0,62,48,1,1,0,0,7,0},   // Tailoring 1
{103,0,0,62,60,48,0,0,0,-1,0,0},   // Malygos
{81,43,0,49,64,0,1,0,1,0,7,0},   // Tailoring 2
{90,56,0,0,63,49,0,0,1,0,5,0},   // Vezax

//Leggings
{124,0,0,66,76,54,0,1,1,2,6,1},   // T8
{132,0,60,0,82,66,1,1,0,0,7,0},   // Vezax 10 Hard
{122,70,77,0,98,0,1,1,1,0,9,0},   // Freya Hard

//Boots
{92,0,61,47,69,0,1,0,1,0,7,0},   // Yogg Hard
{102,0,0,55,72,64,1,1,0,3,6,0},   // Flame Leviathan Hard
{99,56,57,0,60,0,0,0,0,-1,0,0},   // XT002

//Rings
{149,0,46,91,97,39,0,0,1,0,5,0},   // KT+Mimiron Hard
{148,42,46,36,91,22,1,0,0,0,5,0},   // KT+Flame Leviathan 10 Hard
{148,46,46,72,95,0,0,0,0,-1,0,0},   // KT+Hodir Hard
{148,0,92,72,91,0,0,0,0,-1,0,0},   // KT+Ignis

//Trinkets
{354,0,120,0,0,0,0,0,0,-1,0,0},   // Sarth+Vezax Hard
{154,108,120,95,0,0,0,0,0,-1,0,0},   // Vezax Hard+Auraiya
{302,71,120,0,0,0,0,0,0,-1,0,0},   // Vezax Hard+Dying curse

//Weapon
{661,39,0,36,102,88,0,0,1,0,9,0},   // Algalon+Kologarn
{651,39,47,0,100,79,0,0,1,0,9,0},   // Algalon+Ignis
{662,80,0,0,101,85,0,0,1,0,9,0},   // Algalon+Flame Leviathan
{605,0,104,0,128,84,0,0,2,0,9,0},   // Hodir Hard

//Wand
{44,0,18,29,26,0,0,0,0,-1,0,0},   // Vezax
{42,0,0,23,26,24,0,0,0,-1,0,0},   // Ignis
{42,27,0,0,17,20,0,1,0,5,4,0}    // Freya 10 Hard
};

#define TOPN	10

struct gearsetup {
    double dps;
    double spellhit;
    double crit;
    double critPercent;
    double haste;
    double spellPower;
    int gear[15];
} top[TOPN];
  


int n[14]={4,4,5,4,4,4,3,4,3,3,4,3,4,3};
int offset[14]={0};
double pp[6]={1,1.31,0.71,0.65,0.21,0.21};
int main(int argc, char *argv[]){
   int gear[15]={0};
   int i,j,k,l,m;
   int id,bluedef;
   double hitdef;
   double spellHit,crit,haste,spellPower,intellect,spirit,red,yellow,blue,T8,meta=1;
   double dps;
   double shadowWordPain,mindBlast,vampiricTouch,devouringPlaque,mindFlay;
   double ImpSTCover;
   double gcd;
   double critpercent,hitpercent,hastepercent;
   double spellHitCap=263.0; // Hit cap
   int socket[14];
   double pplost[14];
   int socketremain[14][3];
   int *idt[14];
   int tailoring=0;
   int enchanting=0;
   int dontgemforhit=0;
   int dranai=1;
   int iterations=0;
   time_t start,now;
   #ifdef _WIN32
   char input[2];
   #endif

   start=time(&start);
   i=0;
   while(++i<argc) {
    if (!strcmp(argv[i],"-nodranai")) {spellHitCap=289.0;dranai=0;}
    if (!strcmp(argv[i],"-tailoring")) tailoring=1;
    if (!strcmp(argv[i],"-enchanting")) enchanting=1;
    if (!strcmp(argv[i],"-dontgemforhit")) dontgemforhit=1;
   }
   zerobest();
   for(i=1;i<14;i++){
      offset[i]=offset[i-1]+n[i-1];
      if(n[i-1]==0)n[i-1]=n[i-2];
   }
    printf(" DPS     Hit     Crit      Haste     SP  ABCDEFGHIJKLM\n");
   while(gear[14]==0){
// Enchant: Head 30SP+20Crit Shoudlers 24SP+15Crit Cloak 23Haste Chest 10Stats
// Bracers 30SP Gloves 28SP Leggings 50SP+20Spirit Boots Icewalker Weapon 63SP
      crit=47;spellHit=12;haste=23;spellPower=225;
      if (tailoring==1) {
		haste=0;
		spellPower+=250.0*15.0/45.0;
      }
      if (enchanting==1) {
		spellPower+=38; //rings enchants
      }

// Base INT:173, Spirit 187
      intellect=173+10;spirit=187+30;
      red=0;blue=0;yellow=0;
      T8=0;
      for(j=0;j<14;j++){
         idt[j]=itemdata[offset[j]+gear[j]];
         spellPower+=idt[j][0];
         spellHit+=idt[j][1];
         crit+=idt[j][2];
         haste+=idt[j][3];
         intellect+=idt[j][4];
         spirit+=idt[j][5];
         red+=idt[j][6];
         yellow+=idt[j][7];
         blue+=idt[j][8];
         T8+=idt[j][11];
         socket[j]=idt[j][6]+idt[j][7]+idt[j][8];
         socketremain[j][0]=idt[j][6];
         socketremain[j][1]=idt[j][7];
         socketremain[j][2]=idt[j][8];
      }
// Gems
// Find 2 blue sockets with highest bonus for meta
// Yellow to cap hit, otherwise 19sp
      hitdef=spellHitCap-spellHit;
      if(hitdef<0)hitdef=0;
      if(meta==1){
         bluedef=2;
         crit+=21;
      }
      for(j=0;j<14;j++){
         if(socket[j]==0)continue;
         pplost[j]=idt[j][7]*4.32+idt[j][8]*8.32-idt[j][10]*pp[idt[j][9]];
         if(pplost[j]<=0){ // If the bonus is good
            spellPower+=19*idt[j][6]+9*idt[j][8]+9*idt[j][7];
            spirit+=8*idt[j][8];
            crit+=8*idt[j][7];
            bluedef-=idt[j][8];
            red-=idt[j][6];
            yellow-=idt[j][7];
            blue-=idt[j][8];
            socket[j]=0;
            switch(idt[j][9]){
               case 0:spellPower+=idt[j][10];break;
               case 1:spellHit+=idt[j][10];break;
               case 2:crit+=idt[j][10];break;
               case 3:haste+=idt[j][10];break;
               case 4:intellect+=idt[j][10];break;
               case 5:spirit+=idt[j][10];break;
               default:break;
            }
         }
      }
      while(bluedef>0){ // Activate meta
         double p=50;
         for(j=0;j<14;j++){
            if(socket[j]==0)continue;
            if(pplost[j]<p && socketremain[j][2]>0){
               i=j;p=pplost[j];
			   break;
            }
         }
         spellPower+=9;spirit+=8;socket[i]--;blue--;bluedef--;socketremain[i][2]--;
         if(socket[i]==0){
            switch(idt[i][9]){
               case 0:spellPower+=idt[i][10];break;
               case 1:spellHit+=idt[i][10];break;
               case 2:crit+=idt[i][10];break;
               case 3:haste+=idt[i][10];break;
               case 4:intellect+=idt[i][10];break;
               case 5:spirit+=idt[i][10];break;
               default:break;
            }
         }
      }
      if (!dontgemforhit) {
      while(hitdef>4){ // Cap hit
		  double p; 
         if(yellow==0) break;
         
		 if (hitdef>=16) 
			 p=16*1.31;
		 else
			 p=hitdef*1.31;  
         for(j=0;j<14;j++){
            if(socket[j]==0)continue;
            if(pplost[j]<p && socketremain[j][1]>0){
               i=j;p=pplost[j];
			   break;
            }
         }
         if(hitdef>12){
            spellHit+=16;socket[i]--;yellow--;hitdef-=16;socketremain[i][1]--;
         } else {
            spellPower+=9;spellHit+=8;socket[i]--;yellow--;hitdef-=8;socketremain[i][1]--;
         }
         if(socket[i]==0){
            switch(idt[i][9]){
               case 0:spellPower+=idt[i][10];break;
               case 1:spellHit+=idt[i][10];break;
               case 2:crit+=idt[i][10];break;
               case 3:haste+=idt[i][10];break;
               case 4:intellect+=idt[i][10];break;
               case 5:spirit+=idt[i][10];break;
               default:break;
            }
         }
      }
      }
      spellPower+=19*(red+blue+yellow);  // 19 sp
      for(i=0;i<14;i++){
         if(socket[i]==idt[i][6]){
            switch(idt[i][9]){
               case 0:spellPower+=idt[i][10];break;
               case 1:spellHit+=idt[i][10];break;
               case 2:crit+=idt[i][10];break;
               case 3:haste+=idt[i][10];break;
               case 4:intellect+=idt[i][10];break;
               case 5:spirit+=idt[i][10];break;
               default:break;
            }
         }
      }

// RAID Buff : Flask 125SP Food 46SP Inner fire 174SP 5%haste 5%crit MoonkinAura TotemOfWrath(3%Crit 280SP) INT+SPI+MotW+Kings
      if(T8>=4)haste+=240*4/5.5;
      hastepercent=(haste/32.79+5)/100.0;//Haste
      gcd=1.5/(1+hastepercent);
      intellect+=97;
      intellect*=1.1;
      critpercent=(crit/45.91+intellect*3/500+13)/100.0; //Crit
      if(meta==1)critpercent*=1.09; // Meta
      ImpSTCover=8/5.5*critpercent; // Imp Spirit Tap
      if(ImpSTCover>1)ImpSTCover=1;
      spirit+=117;
      spirit*=1.1;
      spirit*=(1+0.1+ImpSTCover); // Imp Spirit Tap+Glyph of shadow
      spellPower+=spirit/10; //Twisted Faith
      spellPower+=345;
      
      hitpercent=((83+6+dranai+spellHit)/26.23)/100.0; //Hit
      if(hitpercent>1)hitpercent=1;
// DPS
      mindBlast=240*(1020+0.579*spellPower)*(1.02+critpercent)*1.1;
      devouringPlaque=55*(1376+1.48*spellPower)*(1.03+critpercent)*1.3*(1+0.05+0.1)*1.3; //2nd 1.3 from Ebon plague
      if(T8>=2)devouringPlaque*=1.15;
      vampiricTouch=88*(850+1.92*spellPower)*(1.03+critpercent)*(1+0.1);
      shadowWordPain=440*(230+0.22*spellPower)*(1.03+critpercent)*(1+0.05+0.06+0.1);
      mindFlay=(1320-383*gcd)/(gcd/1.5)*(196+0.193*spellPower)*(1.02+critpercent)*(1+0.1+0.05)*1.1;
      dps=(mindBlast+devouringPlaque+vampiricTouch+shadowWordPain+mindFlay)/1320;
      dps*=(hitpercent);
      dps*=(1.15*1.1*1.13); // Shadow weaving+Shadow Form+13% dmg
      keepbest(dps,spellHit,crit,critpercent,haste,spellPower,gear);

      gear[0]++;
      for(i=0;i<14;i++){
         if(gear[i]>=n[i]){
            gear[i]=0;
            gear[i+1]++;
         }
      }
      ++iterations;
   }
   printbest();
   now=time(&now);
   double elapsed=difftime(now,start);
   
   printf("Number of iterations: %d Time needed: %.2f secs  (%.2f iterations/sec)\n",iterations,elapsed,iterations/elapsed);
#ifdef _WIN32
   char *ret=fgets(input,2,stdin);
#endif
   return 0;
}

void zerobest(void)
{
  memset(&top,0,sizeof(struct gearsetup) * TOPN);
}
void printbest(void)
{
  int i,j;

  for(i=0; i<TOPN; ++i) {
    printf("%.2f hit=%03.0f crit=%.0f(%.2f%%) haste=%.0f SP=%.0f  ",top[i].dps,top[i].spellhit,top[i].crit,100.0*top[i].critPercent,top[i].haste,top[i].spellPower);
    for(j=0;j<14;j++) printf("%d ",top[i].gear[j]);
    printf("\n");
  }
}

void keepbest(double dps, double hit, double crit,double critpercent, double hast, double sp, int gear[])
{
   int i,j;

   if (dps<=top[TOPN-1].dps) return;
   
   i=TOPN-2;
   while(dps>top[i].dps) {
      --i;
      if (i<0) {
	break;
      }
    }
    ++i;

   for(j=TOPN-1; j>i; --j) memmove(&top[j],&top[j-1],sizeof(struct gearsetup));
   
   top[i].dps=dps;
   top[i].spellhit=hit;
   top[i].crit=crit;
   top[i].critPercent=critpercent;
   top[i].haste=hast;
   top[i].spellPower=sp;
   for(j=0; j<15; ++j)
      top[i].gear[j]=gear[j];
}
